package com.common;

import java.util.concurrent.atomic.AtomicInteger;

//随机选择和轮训选择在样本很大的情况下，是一样的。
@UnstableApi
public final class DefaultEventExecutorChooserFactory implements EventExecutorChooserFactory {

    public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();

    private DefaultEventExecutorChooserFactory() { 
    	
    }

    @SuppressWarnings("unchecked")
    @Override
    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {//nioEventLoopGroup数组的个数，
        	//是否是2的幂次方。是就返回效率高的PowerOfTowEventExecutor
            return new PowerOfTowEventExecutorChooser(executors);
        } else {//否则返回普通的GenericEventExecutor
            return new GenericEventExecutorChooser(executors);
        }
    }

    private static boolean isPowerOfTwo(int val) {//判断是否2个幂次方
    	int j = (val & -val);
    	int k = 15;
    	int tk = -k;//-15
    	int m = (k & -k);//1
    	int k1 = 16;
    	int tk1 = -k1;//-16
    	int m1 = (k1 & -k1);//16
        return (val & -val) == val;
    }

    private static final class PowerOfTowEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        PowerOfTowEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {//每次递增加1与（executors.length - 1）
        	int i = idx.getAndIncrement() & executors.length - 1;
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {//每次递增加1，循环取出来。取模。
        	int i = Math.abs(idx.getAndIncrement() % executors.length);
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }
}
